package com.atguigu.gmall.activity.consumer;

import com.atguigu.gmall.activity.config.CacheHelper;
import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.mq.config.MqConst;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author ：MJS
 * @date ：Created in 2021/5/31  10:13
 * @description：秒杀商品的监听消息实现类
 *
 */
@Component
public class SeckillGoodsConsumer {
    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    //监听   定时任务  半夜将DB存入缓存
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1
    ))
    public void importDBToRedis(Channel channel, Message message){
        try {
            //1:查询DB中秒杀商品
            QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<SeckillGoods>();
            //1）审核通过的
            queryWrapper.eq("status", "1");
            //2）必须是当天
            queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));
            //3）库存大于0
            queryWrapper.gt("stock_count", 0);
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);

            //验证是否为空
            if(!CollectionUtils.isEmpty(seckillGoodsList)){
                seckillGoodsList.forEach(seckillGoods -> {
                    //五大数据类型  使用hash
                    //h SECKILL_GOODS  hk skuId    hv SeckillGoods
                    //2、判断秒杀商品是否已经在缓存中存在了
                    if(!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString())){
                        //3、如果不存在   压入秒杀商品到缓存中
                        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,
                                seckillGoods.getSkuId().toString(),seckillGoods);
                        //4、解决秒杀中的超卖问题
                        //K:常量加skuId  V：一个数组
                        redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX+
                                seckillGoods.getSkuId(),getSkuIds(seckillGoods));
                        // 5 状态位   发送方
                        redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");//有货

                    }
                });
            }

            //手动应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);//不进行批量
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //监听  定时任务
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER
    ))
    public void seckillStart(UserRecode userRecode, Channel channel, Message message) {
//        秒杀微服务
//       1、校验状态位
        String status = (String) CacheHelper.get(userRecode.getSkuId().toString());
        if("0".equals(status)){
            return;
        }
//        2、校验用户是否购买过  setnx   true = setnx(k,v)  没来过返回true  设置新的成功  返回true
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(
                RedisConst.SECKILL_USER + userRecode.getUserId(), "check");
        if(!ifAbsent){
            //用户已经购买过了
            try {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;//代表失败
        }
//        3、校验是否还有货
        Object o = redisTemplate.opsForList().rightPop(
                RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId());
        if(null == o){
            // 更新  所有 秒杀服务的状态位
            redisTemplate.convertAndSend("seckillpush",
                    userRecode.getSkuId()+":0");//无货了
            return;//代表失败
        }
//        4、给用户抢购资格
        redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDERS + userRecode.getUserId()
                ,userRecode);

    }

    //数组   skuId数组
    public String[] getSkuIds(SeckillGoods seckillGoods){
        //剩余库存数量
        String[]ids=new String[seckillGoods.getStockCount()];
        for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
            ids[i]=seckillGoods.getSkuId().toString();
        }
        return ids;
    }

}
